package testJdk.generic;

import java.util.Date;

/**
 * @Description : 类描述
 * Created by cyd on 2021-03-16 21:27:21
 */
public class Test01 {
    // 这个类是个泛型类，在上面已经介绍过
    // 也是一个内部类
    public static class Generic<T> {
        private T key;

        public Generic(T key) {
            this.key = key;
        }

        /**
         * 实例一：
         * 这是最容易混淆的，虽然在方法中使用了泛型，但是这并不是一个泛型方法。
         * 这只是类中一个普通的成员方法，只不过他的返回值是在声明泛型类时，已经声明过的泛型。
         * 所以在这个方法中，才可以继续使用 T 这个泛型。
         */
        public T getKey() {
            return key;
        }

        /*
         * 这个方法显然是有问题的，在编译器会给我们提示这样的错误信息"cannot reslove symbol E"
         * 因为在类的声明中并未声明泛型E，所以在使用E做形参和返回值类型时，编译器会无法识别。
         * public void setKey(E key){
         *     this.key = keu;
         * }
         */

    }

    /**
     * 实例二：
     * 这才是一个真正的泛型方法。
     * 1.首先在public与返回值之间的<T>必不可少，这表明这是一个泛型方法，并且声明了一个泛型T
     * 2.这个T可以出现在这个泛型方法的任意位置.
     * 3.泛型的数量也可以为任意多个
     * 如：
     * public <T,K> K showKeyName(Generic<T> container){
     * ...
     * }
     */
    public <T> T showKeyName(Generic<T> container) {
        System.out.println("container key :" + container.getKey());

        T test = container.getKey();
        return test;
    }

    /**
     * 实例三：
     * 这也不是一个泛型方法，这就是一个普通的方法，
     * 只是使用了Generic<Number>这个泛型类做形参而已。
     *
     * @param obj:Generic类的泛型已经确定是String
     */
    public void showKeyValue1(Generic<String> obj) {
        System.out.println("key value is " + obj.getKey());
    }

    /*
     * 实例四：
     * 这个方法是错的，因为T无法识别
     *
     * public void showKeyValue2(Generic<T> obj) {
     *      System.out.println("key value is " + obj.getKey());
     * }
     *
     */

    /**
     * 实例五：
     * 这也不是一个泛型方法，就是一个普通的方法，只不过使用了泛型通配符?
     *
     * @param obj:意思是现在还不确定里面放什么泛型
     */
    public void showKeyValue2(Generic<?> obj) {
        System.out.println("key value is " + obj.getKey());
    }

    /*
       实例六：
     * 这个方法是有问题的，编译器会为我们提示错误信息："UnKnown class 'E' "
     * 虽然我们声明了<T>,也表明了这是一个可以处理泛型的类型的泛型方法。
     * 但是只声明了泛型类型T，并未声明泛型类型E，因此编译器并不知道该如何处理E这个类型。
        public <T> T showKeyName(Generic<E> container){
            ...
        }
     */

    /**
     * 实例七：
     * 这个方法也是有问题的，编译器会为我们提示错误信息："UnKnown class 'T' "
     * 由于T声明在内部类（其他类）的作用域中,对于编译器来说T这个类型并未在方法上声明过，
     * 因此编译也不知道该如何编译这个类。
     * 所以这也不是一个正确的泛型方法声明。
     * <p>
     * public void showkey(T genericObj){
     * ...
     * }
     *
     * <p>
     * 下面这个方法才正确；
     * 想要使用T，必须先在泛型方法的返回值前面声明；
     */
    public <T> void showkey(T genericObj) {
        System.out.println(genericObj);
    }

    public static void main(String[] args) {
        Test01 test01 = new Test01();
        // 调用泛型方法，此处传入任何类型都可以
        test01.showkey("123456");
        test01.showkey(123456);

        System.out.println("------测试showKeyValue1------");
        test01.showKeyValue1(new Generic<String>("123"));

        System.out.println("------测试showKeyValue2------");
        test01.showKeyValue2(new Generic<Float>(12345.6f));

        // 测试实例八，此处传入任何类型都可以
        Generic<Integer> generic01 = new Generic<>(1);
        Integer key01 = generic01.getKey();
        System.out.println(key01);

        Generic<Date> generic02 = new Generic<>(new Date());
        Date key02 = generic02.getKey();
        System.out.println(key02);
    }

}
